`timescale 1ns / 1ps

module top(
           clk,
           resetb,
           ps2_rxc,
           ps2_rxd,
           // -----------------
           vga_clk,
           vga_dat,
           vga_blk_n,
           vga_sync_n,
           vga_hs,
           vga_vs,
           // ----------------------
           ov_scl,
           ov_sda,
           ov_pwdn,
           ov_vsync,
           ov_hsync,
           ov_pclk,
           ov_idat,
           // -------------------
           sdr_sa,
           sdr_ba,
           sdr_cs_n,
           sdr_cke,
           sdr_ras_n,
           sdr_cas_n,
           sdr_we_n,
           sdr_dq,
           sdr_dqm,
           sdr_clk,
           // ------------------
           sel_seg,
           HEX0, HEX1, HEX2, HEX3, HEX4, HEX5,
           MODE_SEL
       );

parameter ADDR1_MAX = 800 * 600;
parameter ADDR2_MAX = 800 * 600 * 2;

input clk;
input resetb;
input ps2_rxc;
input ps2_rxd;

output vga_clk;
output [23: 0] vga_dat;
output vga_blk_n;
output vga_sync_n;
output vga_hs;
output vga_vs;

output [12: 0] sdr_sa; //sdram address output
output [1: 0] sdr_ba; //sdram bank address
output sdr_cs_n; //sdram chip selects
output sdr_cke;  //sdram clock enable
output sdr_ras_n; //sdram row address strobe
output sdr_cas_n; //sdram column address strobe
output sdr_we_n; //sdram write enable
input [15: 0] sdr_dq; //sdram data bus
output [1: 0] sdr_dqm; //sdram data mask lines
output sdr_clk; //sdram clock

output ov_scl;
inout ov_sda;
output ov_pwdn;
input ov_vsync;
input ov_hsync;
input ov_pclk;
input [7: 0] ov_idat;

input sel_seg;
output [6: 0] HEX0, HEX1, HEX2, HEX3, HEX4, HEX5;
input MODE_SEL;

//system pll
wire outclk_0;
wire outclk_1;
wire outclk_2;
wire outclk_3;
wire outclk_4;
wire locked;
wire resetb_0 = resetb & locked;

pll_top u_pll_top(
            .clk(clk),
            .resetb(resetb),
            .outclk_0(outclk_0),
            .outclk_1(outclk_1),
            .outclk_2(outclk_2),
            .outclk_3(outclk_3),
            .outclk_4(outclk_4),
            .locked(locked)
        );

//ov7725 senser
wire sdram_init_done;
wire finish;
i2c u_i2c(
        .sys_clk(outclk_0),
        .rst(resetb_0 & sdram_init_done),
        .scl(ov_scl),
        .sda(ov_sda),
        .finish(finish)
    );

assign ov_pwdn = 1'b0;

// controller
wire cmd;
wire [9: 0] cdat;
controller u_controller(
               .clk(outclk_0),
               .resetb(resetb_0),
               .rxc(ps2_rxc),
               .rxd(ps2_rxd),
               .oe(cmd),
               .odat(cdat)
           );

//ov_idat2rgb
wire [15: 0] rgb;
wire vsync_w0;
wire hsync_w0;
wire clken_w0;

idat_rx u_idat_rx(
            .clk(ov_pclk),
            .resetb(resetb & finish),
            .idat(ov_idat),
            .odat(rgb),
            .ivsync(ov_vsync),
            .ihsync(ov_hsync),
            .ovsync(vsync_w0),
            .ohsync(hsync_w0),
            .oclken(clken_w0),
            .mode(MODE_SEL)
        );

wire [7: 0] ogray;
wire oclken_g;
wire ohsync_g;
wire ovsync_g;

rgb2gray u_rgb2gray(
             .clk(ov_pclk),
             .clken(clken_w0),
             .rgb(rgb),
             .resetb(resetb),
             .ihsync(hsync_w0),
             .ivsync(vsync_w0),
             .gray(ogray),
             .oclken(oclken_g),
             .ohsync(ohsync_g),
             .ovsync(ovsync_g)
         );

wire [7: 0] rdat1;
wire oe_sft;
wire [15: 0] gray_sft;
wire sdr_rd;

gray_shift u_gray_shift(
               .clk(ov_pclk),
               .resetb(resetb),
               .clken(oclken_g),
               .ivsync(ovsync_g),
               .ihsync(ohsync_g),
               .graya(ogray),        //next frame
               .grayb(rdat1),        //before frame
               .oe(oe_sft),
               .sdr_rd(sdr_rd),
               .ogray(gray_sft)
           );

wire oe_dif;
wire odat_dif;
wire sel;
difference u_difference(
               .clk(ov_pclk),
               .resetb(resetb),
               .ie(oe_sft),
               .idat(gray_sft),
               .oe(oe_dif),
               .odat(odat_dif),
               .sel(sel),
               .cmd(cmd),
               .T_Dat(cdat)
           );

wire rd_sel;
wire rd_vga;
wire odat_ram0;
wire odat_ram1;
dif_ram u_dif_ram0(
            .resetb(resetb),
            .sel(~rd_sel),
            .wclk(ov_pclk),
            .wr(oe_dif & sel),
            .wdat(odat_dif),
            .rclk(outclk_1),
            .rd(rd_vga),
            .rdat(odat_ram0)
        );

dif_ram u_dif_ram1(
            .resetb(resetb),
            .sel(rd_sel),
            .wclk(ov_pclk),
            .wr(oe_dif & ~sel),
            .wdat(odat_dif),
            .rclk(outclk_1),
            .rd(rd_vga),
            .rdat(odat_ram1)
        );

rd_sel u_rd_sel(
           .clk(outclk_1),
           .resetb(resetb),
           .rd(rd_vga),
           .isel(sel),
           .osel(rd_sel)
       );

//sdr controller
wire wr1 = oe_sft;
wire wr2 = clken_w0 & hsync_w0 & vsync_w0;
wire [7: 0] wdat1 = gray_sft[15: 8];
wire [15: 0] wdat2 = rgb;
wire [15: 0] rdat2;

Sdram_Control_2Port u_sdr(
                        //host side
                        .REF_CLK(outclk_3),      //sdram control clock
                        .OUT_CLK(outclk_4),      //sdram output clock
                        .RESET_N(resetb_0),      //global clock reset
                        //fifo write side 1
                        .wdat1(wdat1),
                        .wr1(wr1),
                        .waddr1_min(0),
                        .waddr1_max(ADDR1_MAX),
                        .wr1_length(64),
                        .wr1_load(~resetb_0),
                        .wr1_clk(ov_pclk),
                        //fifo write side 2
                        .wdat2(wdat2),
                        .wr2(wr2),
                        .waddr2_min(ADDR1_MAX),
                        .waddr2_max(ADDR2_MAX),
                        .wr2_length(64),
                        .wr2_load(~resetb_0),
                        .wr2_clk(ov_pclk),
                        //fifo read side 1
                        .rdat1(rdat1),
                        .rd1(sdr_rd),
                        .raddr1_min(0),
                        .raddr1_max(ADDR1_MAX),
                        .rd1_length(64),
                        .rd1_load(~resetb_0),
                        .rd1_clk(ov_pclk),
                        //fifo read side 1
                        .rdat2(rdat2),
                        .rd2(rd_vga),
                        .raddr2_min(ADDR1_MAX),
                        .raddr2_max(ADDR2_MAX),
                        .rd2_length(64),
                        .rd2_load(~resetb_0),
                        .rd2_clk(outclk_1),
                        //sdram side
                        .SA(sdr_sa),
                        .BA(sdr_ba),
                        .CS_N(sdr_cs_n),
                        .CKE(sdr_cke),
                        .RAS_N(sdr_ras_n),
                        .CAS_N(sdr_cas_n),
                        .WE_N(sdr_we_n),
                        .DQ(sdr_dq),
                        .DQM(sdr_dqm),
                        .SDR_CLK(sdr_clk),
                        //user interface
                        .Sdram_Init_Done(sdram_init_done),      //sdram init done signal
                        .Sdram_Read_Valid(1'b1)  //sdram read valid:output
                    );

//vga driver
wire resetb_1 = resetb_0 & sdram_init_done & finish;
wire odat_ram = rd_sel ? odat_ram1 : odat_ram0;
//wire [23:0] rdat_rgb888 = 24'hff0000;
wire [10: 0] hcnt;
wire [10: 0] vcnt;
wire [10: 0] x_max;
wire [10: 0] x_min;
wire [10: 0] y_max;
wire [10: 0] y_min;

vga_driver u_vga(
               .clk(outclk_1),
               .oclk(outclk_2),
               .resetb(resetb_1),
               .vga_clk(vga_clk),
               .vga_dat(vga_dat),
               .vga_blk_n(vga_blk_n),
               .vga_sync_n(vga_sync_n),
               .vga_hs(vga_hs),
               .vga_vs(vga_vs),
               .rd(rd_vga),
               .rdat(rdat2),
               .hcnt(hcnt),
               .vcnt(vcnt),
               .x_max(x_max),
               .x_min(x_min),
               .y_max(y_max),
               .y_min(y_min)
           );
wire idat_pos = rd_vga ? ~odat_ram : 1'b0;

wire oe_pos;
position u_pos(
             .clk(outclk_1),
             .resetb(resetb),
             .ie(rd_vga),
             .hcnt(hcnt),
             .vcnt(vcnt),
             .idat(idat_pos),
             .oe(oe_pos),
             .x_max(x_max),
             .x_min(x_min),
             .y_max(y_max),
             .y_min(y_min)
         );

wire [11: 0] x_pos = ({1'b0, x_max} + {1'b0, x_min} - 12'd430);
wire [11: 0] y_pos = ({1'b0, y_max} + {1'b0, y_min} - 12'd54);

segment u_seg(
            .clk(outclk_0),
            .resetb(resetb),
            .cmd(cmd),
            .cdat(cdat),
            .x_pos(x_pos[11: 1]),
            .y_pos(y_pos[11: 1] + 1'b1),
            .sel_seg(sel_seg),
            .HEX0(HEX0),
            .HEX1(HEX1),
            .HEX2(HEX2),
            .HEX3(HEX3),
            .HEX4(HEX4),
            .HEX5(HEX5)
        );

endmodule
